package com.wlr.littleprogram.aspect;

import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

@Aspect
@Component
public class HttpRequestAspect {
    private final Logger log = LoggerFactory.getLogger(getClass().getName());

    /**
     * 环绕方法执行，获取执行时间
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("@annotation(com.wlr.littleprogram.aspect.LogTrack)")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // 获取被代理的方法参数
        Object[] args = proceedingJoinPoint.getArgs();
        // 获取被代理的对象
        Object target = proceedingJoinPoint.getTarget();
        // 获取通知签名
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        // 获取被代理的方法
        Method pointMethod = proceedingJoinPoint.getTarget().getClass()
                .getMethod(signature.getName(), signature.getParameterTypes());
        // 判断该注解有没有注册在代理方法上
        LogTrack logTrack = pointMethod.getAnnotation(LogTrack.class);
        if (logTrack == null) {
            logTrack = target.getClass().getAnnotation(LogTrack.class);
        }
        if (logTrack != null) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            assert attributes != null;
            HttpServletRequest request = attributes.getRequest();
            if ("".equals(logTrack.value())) {
                log.info("前端请求信息");
                log.info("方法名：{}.{}", proceedingJoinPoint.getSignature().getDeclaringTypeName(), proceedingJoinPoint.getSignature().getName());
                log.info("请求IP：{}", request.getRemoteAddr());
                log.info("请求方式：{}", request.getMethod());
                log.info("请求参数：{}", JSON.toJSONString(proceedingJoinPoint.getArgs()));
            } else {
                log.info("落表测试");
            }

        }
        return proceedingJoinPoint.proceed();
    }

    /**
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("@annotation(com.wlr.littleprogram.aspect.LogAround)")
    public Object doAround2(ProceedingJoinPoint joinPoint) throws Throwable {
        // 目标类的名称
        String className = joinPoint.getTarget().getClass().getName();
        // 方法名称
        String methodName = joinPoint.getSignature().getName();
        // 参数列表
        Parameter[] parameters = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameters();
        Object[] args = joinPoint.getArgs();

        StringBuilder params = new StringBuilder("[");
        for (int i = 0; i < parameters.length; i++) {
            params.append(parameters[i].getName()).append(":").append(args[i]).append("; ");
        }
        if (parameters.length > 0) {
            int length = params.length();
            params.delete(length - 2, length);
        }
        params.append("]");
        log.info(">>>> Target class name={} | method name={} | params={} <<<<", className, methodName, params);
        Object result = null;
        try {
            // 执行方法
            result = joinPoint.proceed();
        } catch (Exception e) {
            // 记录异常日志
            log.error(">>>> Target class name={} | method name={}\n{}\n\t at {} <<<<", className, methodName, e.toString(), e.getStackTrace()[0]);
            throw e;
        }
        // 记录方法结果
        log.info(">>>> Target class name={} | method name={} | results={} <<<<", className, methodName, JSON.toJSON(result));
        return result;
    }
}
